<HTML>
<head>
	<link href="http://www.codeproject.com/styles/global.css" type="text/css" rel="stylesheet">
	<title>Guadagno Task Scheduler</title>
</head>
<body>
	
	<h2>Contents</h2>
	<ul>
		<li><a href="#Introduction">Introduction</a></li>
		<li><a href="#Application">Application</a></li>
		<ul>
			<li><a href="#Folder_Structure">Folder Structure</a></li>
			<li><a href="#Configuration_File">Configuration File</a></li>
			<ul>
				<li><a href="#Configuration_File_Schema">Configuration File Schema</a></li>
				<li><a href="#The_PluginPath_Property">The PluginPath Property</a></li>
				<li><a href="#The_log4net_Property">The log4net Property</a></li>
			</ul>
		</ul>
		<li><a href="#Creating_A_Task">Creating a Plug-in or Task</a></li>
		<ul>
			<li><a href="#Task_Configuration">Configuration</a></li>
			<ul><li><a href="#The_Schedule_Property">The Schedule Property</a></li></ul>
		</ul>
		<li><a href="#Next_Steps">Next Steps / Future Features</a></li>
		<li><a href="#History">History</a></li>
		<li><a href="#References">References</a></li>
	</ul>
	<h2><a name="Introduction">Introduction</a></h2>
	The Guadagno Task Scheduler is a Windows Service application that allows you to create tasks that can be scheduled to run 
	in a variety of different times and patterns.  The task are .NET v2.0 assemblies that inherit from the <code>ITaskPlugin</code> Interface.
	For more information on the <code>ITaskPlugin</code> interface, please visit the CodeProject article at 
	<a href="http://www.codeproject.com/useritems/taskplugin.asp">http://www.codeproject.com/useritems/taskplugin.asp</a> or the project homepage on SourceForge 
	at <a href="http://taskplugin.sourceforge.net">http://taskplugin.sourceforge.net</a>.
	<h2><a name="Application">Application</a></h2>
	<p>The Guadagno Task Scheduler will look for tasks (plug-ins) to execute by searching the directory specified in the PluginPath configuration section 
	(see the <a href="#Task_Configuration">Configuration section</a>). If this value is not found, the default directory of Plugins folder beneath the 
		root of the installation will be used.</p>
	<h3><a name="Folder_Structure">Folder Structure</a></h3>
	
	<table border=0>
		<tr><TD>Folder</TD><TD>&nbsp;</TD><TD></TD></tr>
		<tr><TD>Installation Directory</TD><TD>&nbsp;</TD><TD>Contains the task scheduler and support files.</td></tr>
		<tr><TD>&nbsp;&nbsp;\Logs</TD><TD>&nbsp;</TD><TD>Contains the log files for the task scheduler and plug-ins</TD></tr>
		<tr><TD>&nbsp;&nbsp;\Plugins</TD><TD>&nbsp;</TD><TD>Contains the plug-ins (the default directory that the task scheduler looks in for plug-ins.</td></tr>
	</table>
	<h3><a name="Configuration_File">Configuration File</a></h3>
	The Guadagno Task Scheduler does not use the typical .NET configuration file, the application uses a XML file for configuration that derives from the
	<code>Guadagno.Utilities.Configuration.ConfigurationBase</code> class. Look for an article on this class in the near future.  This class allows for you to
	dynamically change the configuration or provide different configuration parameters depending on the name of the machine the application 
	is running on. </p>
	
	<h4><a name="Configuration_File_Schema">Configuration File Schema</a></h4>
		<pre lang="xml">
&lt;application.settings stage="auto"&gt;
	&lt;hosts&gt;
		&lt;host name="uatMachinename" stage="uat" comment="" /&gt;				
		&lt;host name="prodMachinename" stage="prod" comment="" /&gt;				
	&lt;/hosts&gt;
	&lt;stage name="default"&gt;
	&lt;!-- Default configuration settings --&gt;
	&lt;/stage&gt;
	&lt;stage name="uat"&gt;
	&lt;!-- UAT configuration settings --&gt;
	&lt;/stage&gt;
	&lt;stage name="prod"&gt;
	&lt;!-- Production configuration settings --&gt;
	&lt;/stage&gt;
&lt;/application.settings&gt;
	</pre>
	
	<p>The root element of the configuration file is <code>&lt;application.settings&gt;</code> element.  The <code>&lt;application.settings&gt;</code> 
	has 2+ child nodes, <code>&lt;hosts&gt;</code> and <code>&lt;stage&gt;</code>.  The <code>&lt;application.settings&gt;</code> has an attribute named 
	<code>stage</code> which indicates which <code>stage</code> element to load.  The <code>&lt;stage&gt;</code> attribute can contain 
	one of the following values:</p>
	<table>
		<tr><TD colspan=3><code>&lt;application.settings stage="<i>Value</i>"&gt;</code></TD></tr>
		<tr><TD>auto</TD><TD>&nbsp;</TD><TD>A value of auto reads the machine name that is the service is running on an looks in the <code>&lt;hosts&gt;</code> section for the
			appropriate stage to load.</td></tr>
		<tr><TD>stage name</TD><TD>&nbsp;</TD><TD>Explicitly loads the stage.</td></tr>
	</table>
	<p>
	The <code>default</code> stage is always read and used to provide the default values for the properties of the application. After the default section is
	read, the configuration class will load the configuration based on the <code>stage</code> attribute for the <code>&lt;application.settings&gt;</code> element.
	</p>

	<h4><a name="The_PluginPath_Property">The PluginPath Property</a></h4>
	This property is used to instruct the Guadagno Task Scheduler the directory you wish to use. This property overrides the default directory of \Plugins 
	underneath the installation directory.
	<h4><a name="The_log4net_Property">The log4net Property</a></h4>
	This property is used to provide the <a href="http://logging.apache.org/log4net/">log4net</a> configuration for the Guadagno Task Scheduler.  The basic configuration 
	provides a number of different log4net appenders, rollingFile, telnet and smtp.
	<h2><a name="Creating_A_Task">Creating a Plug-In or Task</a></h2>
	<p>Creating a Plug-in or Task is as easy as implementing the <code>ITaskPlugin</code> interface.  This interface is provided in the .NET assembly TaskPluginInterface.dll.</p>
	<p><img src="ITaskPlugin_Interface.png"></p>
	A sample implementation of the <code>ITaskPlugin</code> Interface.  For a more complete example, please refer to the article 
	'<a href="http://www.codeproject.com/useritems/taskplugin.asp">A Flexible .NET Plug-in Architecture, by Joseph Guadagno</a>'.
	<pre lang="cs">
[TaskPluginInterface.Plugin(PluginType.Unknown)]
public class PluginShell : ITaskPlugin
{
	#region ITaskPlugin Members
	#region ITaskPlugin Properties

	public string Name
	{
		get { return "My sample Task"; }
	}

	public string Description
	{
		get { return "My first test plug-in"; }
	}

	public string Extension
	{
		get { return "The extension that this plug-in handles (not implemented)"; }
	}
	
	public string ExtensionDescription
	{
		get { return "A description of the extension (not implemented)"; }
	}
	
	public string Version
	{
		get { return "1.0.0.1"; }
	}
	
	public string Author
	{
		get { return "Joseph Guadagno"; }
	}
	
	public List<IScheduledItem> Schedule
	{
		get { return m_Schedule; }
	}

	#endregion ITaskPlugin Properties

	#region ITaskPlugin Methods

	public ExecuteResult Execute()
	{

		try
		{
		    // Setup the Progress Information
		    m_Progress.TotalTasks = 1;
		    m_Progress.TotalItems = 1;
		    m_Progress.CurrentTask = 0;
		    m_Progress.CurrentItem = 0;
		    m_Cancel = false;
		
		    m_Log.Debug(Properties.Resources.Execute_Started);
		
		    // If the EventStart event has been subscribed to let's fire it.
		    if (EventStart != null)
		        EventStart(this, new PluginEventArgs(m_Progress, "Starting the task.", null));
		
		    DoWork();
		
		    // If the EventStart event has been subscribed to let's fire it.
		    if (EventEnd != null)
		    {
		        if (m_Cancel)
		        {
		            EventEnd(this, new PluginEventArgs(m_Progress, "Task execution was cancelled.", null));
		        }
		        else
		        {
		            EventEnd(this, new PluginEventArgs(m_Progress, "Task execution is complete.", null));
		        }
		    }
	
	      // Exit 
	      if (m_Cancel)
	      {
	          m_Log.DebugFormat(Properties.Resources.Execute_Ended, ExecuteResult.Cancelled);
	          return ExecuteResult.Cancelled;
	      }
	      else
	      {
	          m_Log.DebugFormat(Properties.Resources.Execute_Ended, ExecuteResult.Ok);
	          return ExecuteResult.Ok;
	      }
	  }
	  catch (Exception ex)
	  {
	      if (EventExceptionOccurred != null)
	          EventExceptionOccurred(this, new PluginEventArgs(m_Progress, "", ex));
	
	      // Exit with an Exception
	      return ExecuteResult.Exception;
	  }

	}

	public bool Cancel()
	{
	    m_Log.Debug(Properties.Resources.CancelMethodExecuted);
	    m_Cancel = true;
	    return true;
	}
	#endregion ITaskPlugin Methods
	
	#region ITaskPlugin Events
	public event OnStart EventStart;
	public event OnEnd EventEnd;
	public event OnProcessing EventProcessing;
	public event OnExceptionOccurred EventExceptionOccurred;
	#endregion ITaskPlugin Events
	
	#endregion

	#region Private Methods
	
	/// <summary>
	/// Sample subroutine to demonstrate how to execute work.
	/// </summary>
	/// <returns></returns>
	private ExecuteResult DoWork()
	{
	
	    int longLoop = 120;
	    // Reset the currentItem counter
	    m_Progress.CurrentItem = 0;
	    // Set the numbers of items to process
	    m_Progress.TotalItems = longLoop;
	
	    m_Log.Debug(Properties.Resources.StartingToDoWork);
	
	    for (int x = 1; x < longLoop; x++)
	    {
	        // Just Sleep for a half of a second
	        System.Threading.Thread.Sleep(50);
	
	        m_Log.DebugFormat(Properties.Resources.WorkingOn, x);
	
	        // Update the current item
	        m_Progress.CurrentItem = x;
	        if (EventProcessing != null)
	        {
	            PluginEventArgs evt = new PluginEventArgs(m_Progress, "Working", null);
	            EventProcessing(this, evt);
	            if (evt.Cancel == true)
	            {
	                m_Log.Debug(Properties.Resources.CancelRequestRecieved);
	                m_Cancel = true;
	                break;
	            }
	        }
	    }
	
	    if (m_Cancel)
	        return ExecuteResult.Cancelled;
	    else
	    {
	        m_Progress.CurrentTask++;
	        return ExecuteResult.Ok;
	    }
	
	}
	
	#endregion Private Methods
}
	</pre>

	<h3><a name="Task_Configuration">Configuration</a></h3>
	<h4><a name="The_Schedule_Property">The Schedule Property</a></h4>
	<p>The schedule for each task is provided by the task itself.  Once the Task Scheduler "discovers" a task within it's plug-in directory 
	it will retrieve the schedule by examining the schedule property.  The scheduling component uses the .NET scheduled timer library written
	by Andrew Brummer (see reference <a href="#References">below</a>).</p>
	<p>The plug-in can "hard code" the schedule, which is not recommended, or load it from a configuration file. To make it easier for placing the
		schedule in a configuration file. I encapsulated the different schedule types (<code>IScheduledItem</code>) available from the .NET scheduled
	timer library into a XML file and provided a utility function, <code lang="cs">TaskPluginInterface.ScheduleConfig.Load()</code> to parse the configuration.</p>
An example configuration file:</p>
	<pre lang="xml">
&lt;Schedule&gt;
	&lt;ScheduledTime Base="ByMinute" Offset="1,0" /&gt;
	&lt;SimpleInterval StartTime="1/7/08" Interval="5" EndTime="1/15/08"/&gt;
	&lt;SimpleInterval StartTime="1/1/08" Interval="15" /&gt;
	&lt;SimpleInterval StartTime="1/2/08" Interval="20" Count="5"/&gt;
	&lt;SingleEvent EventTime="1/15/08" /&gt;
	&lt;EventQueue&gt;
		&lt;ScheduledTime Base="ByMinute" Offset="15,0" /&gt;
		&lt;ScheduledTime Base="ByMinute" Offset="30,0" /&gt;
	&lt;/EventQueue&gt;
	&lt;BlockWrapper Base="Daily" BeginOffset="6:00 AM" EndOffset="5:00 PM"&gt;
		&lt;ScheduledTime Base="ByMinute" Offset="15,0" /&gt;
	&lt;/BlockWrapper&gt;
&lt;/Schedule&gt;
   </pre>
	
		<p>For more details on the TaskPluginInterface, please checkout the CodeProject article at 
			<a href="http://www.codeproject.com/useritems/taskplugin.asp">http://www.codeproject.com/useritems/taskplugin.asp</a> or 
			the project page at <a href="http://taskplugin.sourceforge.net">http://taskplugin.sourceforge.net</a>.
		</p>
	
	
	<h2><a name="Next_Steps">Next Steps / Future Features</a></h2>
		<ul>
			<li>Refresh / Reload the plug-ins when there are directory changes</li>
			<li>Enable the plug-ins to have / use their own log files</li>
		</ul>
	<h2<a name="History">History</a></h2>
	<table width="100%" border="1">
		<tr><td width="25%">Version</td><td width="25%">Date</td><td width="50%">What was done</td></tr>
		<tr>
			<td>1.0.0.1</td>
			<td>5/14/07</td>
			<td>Created the initial release of the file.</td>
		</tr>
	</table>
	<h2><a name="References">References</a></h2>
	<ul>
		<li>A Flexible .NET Plug-in Architecture, by Joseph Guadagno (<a href="http://www.codeproject.com/useritems/taskplugin.asp">http://www.codeproject.com/useritems/TaskPlugin.asp</a>)</li>
		<li>.NET Scheduled Timer, by Andy Brummer (<a href="http://www.codeproject.com/dotnet/ABTransClockArticle.asp">http://www.codeproject.com/dotnet/ABTransClockArticle.asp</a>)</li>
		<li>Work Queue based multi-threading, by Richard Schneider (<a href="http://www.codeproject.com/cs/threads/workqueuethreading.asp">http://www.codeproject.com/cs/threads/workqueuethreading.asp</a></li>
		<li>log4Net (<a href="http://logging.apache.org/log4net/">http://logging.apache.org/log4net/</a>)</li>
	</ul>
</body>
</HTML>